#include <brpc/server.h>
#include <butil/logging.h>
#include <regex>

#include "data/es.hpp"
#include "data/mysql.hpp"
#include "data/mysql_relation.hpp"
#include "data/mysql_chat_session.hpp"
#include "data/mysql_chat_session_member.hpp"
#include "data/mysql_apply.hpp"

#include "channel.hpp"
#include "etcd.hpp"
#include "utils.hpp"

#include "base.pb.h"
#include "user.pb.h"
#include "friend.pb.h"
#include "message.pb.h"

namespace im
{
    class FriendServiceImpl : public FriendService
    {
    public:
        FriendServiceImpl(
            const std::shared_ptr<elasticlient::Client> &es_client,
            const std::shared_ptr<odb::database> &mysql_client,
            const ServiceManager::ptr &channel_manager,
            const std::string &user_service_name,
            const std::string &message_service_name) :
            _mysql_relation(std::make_shared<RelationTable>(mysql_client)),
            _mysql_apply(std::make_shared<FriendApplyTable>(mysql_client)),
            _mysql_chat_session(std::make_shared<ChatSessionTable>(mysql_client)),
            _mysql_chat_session_member(std::make_shared<ChatSessionMemberTable>(mysql_client)),
            _es_user(std::make_shared<ESUser>(es_client)),
            _user_service_name(user_service_name),
            _message_service_name(message_service_name),
            _mm_channels(channel_manager)
        {
            _es_user->createIndex();
        }

        virtual void GetFriendList(::google::protobuf::RpcController* controller,
                       const ::im::GetFriendListReq* request,
                       ::im::GetFriendListRsp* response,
                       ::google::protobuf::Closure* done){
            LOG_INFO("收到来自 {} 的 获取好友列表 请求！", request->request_id());
            brpc::ClosureGuard done_guard(done);
            auto err_response = [response](const std::string &rid, const std::string &msg){
                response->set_request_id(rid);
                response->set_success(false);
                response->set_errmsg(msg);
            };

            // 1. 获取请求中的用户 ID
            std::string rid = request->request_id();
            std::string user_id = request->user_id();
            // 2. 根据用户 ID，从数据库的好友关系表&用户表中取出该用户所有的好友简息
            std::vector<std::string> friend_list = _mysql_relation->friends(user_id);

            // 3. 根据好友简息中的好友头像 ID，批量获取头像数据，组织完整用户信息结构
            std::unordered_set<std::string> user_ids(friend_list.begin(), friend_list.end());
            std::unordered_map<std::string, UserInfo> userinfo_list;
            if(GetUserInfo(rid, user_ids, userinfo_list) == false){
                return err_response(rid, "获取用户信息失败");
            }

            // 4. 组织响应，将好友列表返回给网关
            response->set_request_id(rid);
            response->set_success(true);
            response->set_errmsg("");
            for(const auto &u : userinfo_list){
                auto* user = response->add_friend_list();
                user->CopyFrom(u.second);
            }
        }
        
        virtual void FriendRemove(::google::protobuf::RpcController* controller,
                            const ::im::FriendRemoveReq* request,
                            ::im::FriendRemoveRsp* response,
                            ::google::protobuf::Closure* done){
            LOG_INFO("收到来自 {} 的 删除好友 请求！", request->request_id());
            brpc::ClosureGuard done_guard(done);
            auto err_response = [response](const std::string &rid, const std::string &msg){
                response->set_request_id(rid);
                response->set_success(false);
                response->set_errmsg(msg);
            };
            // 1. 取出请求中的删除者 ID 和被删除者 ID
            std::string rid = request->request_id();
            std::string user_id = request->user_id();
            std::string friend_id = request->peer_id();
            // 2. 从用户好友关系表中删除相关关系数据，从会话表中删除单聊会话，从会话成员表中删除会话成员信息
            if(_mysql_relation->remove(user_id, friend_id) == false){
                return err_response(rid, "删除好友关系失败");
            }
            // LOG_DEBUG("删除好友关系成功, 好友id:{}", friend_id);
            if(_mysql_chat_session->remove(user_id, friend_id) == false){
                return err_response(rid, "删除会话失败");
            }
            // LOG_DEBUG("删除会话成功");
            // 3. 组织响应，返回给网关
            response->set_request_id(rid);
            response->set_success(true);
            response->set_errmsg("");
        }

        virtual void FriendAdd(::google::protobuf::RpcController* controller,
                            const ::im::FriendAddReq* request,
                            ::im::FriendAddRsp* response,
                            ::google::protobuf::Closure* done){
            LOG_INFO("收到来自 {} 的 发送添加好友申请 请求！", request->request_id());
            brpc::ClosureGuard done_guard(done);
            auto err_response = [response](const std::string &rid, const std::string &msg){
                response->set_request_id(rid);
                response->set_success(false);
                response->set_errmsg(msg);
            };
            // 1. 取出请求中的请求者 ID，和被请求者 ID
            std::string rid = request->request_id();
            std::string user_id = request->user_id();
            std::string friend_id = request->respondent_id();
            // 2. 判断两人是否已经是好友
            // bool ret = ;
            if(_mysql_relation->is_friend(user_id, friend_id) == true){
                std::string errmsg = friend_id + "是你的好友";
                return err_response(rid, errmsg);
            }
            // 3. 判断该用户是否已经申请过好友关系
            if(_mysql_apply->exists(user_id, friend_id)){
                std::string errmsg =  "你已经申请过" + friend_id +"的好友关系";
                return err_response(rid, errmsg);
            }
            // 4. 向好友申请事件表中，新增申请信息
            FriendApply friend_apply(user_id, friend_id);
            if(_mysql_apply->insert(friend_apply) == false){
                std::string errmsg = "申请好友关系失败";
                return err_response(rid, errmsg);
            }
            // 5. 组织响应，将事件 ID 信息响应给网关
            response->set_request_id(rid);
            response->set_success(true);
            response->set_errmsg("");
        }

        virtual void FriendAddProcess(::google::protobuf::RpcController* controller,
                            const ::im::FriendAddProcessReq* request,
                            ::im::FriendAddProcessRsp* response,
                            ::google::protobuf::Closure* done){
            LOG_INFO("收到来自 {} 的 处理好友申请 请求！", request->request_id());
            brpc::ClosureGuard done_guard(done);
            auto err_response = [response](const std::string &rid, const std::string &msg){
                response->set_request_id(rid);
                response->set_success(false);
                response->set_errmsg(msg);
            };
            // 1. 取出请求中的申请人 ID，和被申请人 ID，以及处理结果
            std::string rid = request->request_id();
            std::string eid = request->notify_event_id();
            std::string user_id = request->user_id();           // 被申请人
            std::string apply_user_id = request->apply_user_id();   // 申请人的用户id
            bool agree = request->agree();
            // 2. 根据两人 ID 在申请事件表中查询判断是否存在申请事件
            if(_mysql_apply->exists(apply_user_id, user_id) == false){
                std::string errmsg = apply_user_id + "没有申请过你的好友关系";
                return err_response(rid, errmsg);
            }
            // 3. 判断两人是否已经是好友（互相加好友的情况）
            if(_mysql_relation->is_friend(apply_user_id, user_id)){
                std::string errmsg = "你已经是" + user_id + "的好友";
                return err_response(rid, errmsg);
            }
            // 4. 不管拒绝还是同意，删除申请事件表中的事件信息（该事件处理完毕）
            if(_mysql_apply->remove(apply_user_id, user_id) == false){
                std::string errmsg = "删除申请事件失败";
                return err_response(rid, errmsg);
            }
            // 5. 若同意申请，则向用户关系表中添加好友关系数据，向会话表中新增会话信息，向会话成员表中新增成员信息
            std::string ssid;
            if(agree){
                // 关系表
                if(_mysql_relation->insert(apply_user_id, user_id) == false){
                    std::string errmsg = "添加好友关系失败";
                    return err_response(rid, errmsg);
                }
                // 会话表
                ssid = uuid();
                ChatSession chat_session(ssid, "", ChatSessionType::SINGLE);
                if(_mysql_chat_session->insert(chat_session) == false){
                    std::string errmsg = "添加会话失败";
                    return err_response(rid, errmsg);
                }
                // 会话成员表
                ChatSessionMember csm1(ssid, user_id);
                ChatSessionMember csm2(ssid, apply_user_id);
                std::vector<ChatSessionMember> mlist = {csm1, csm2};
                ChatSessionMember chat_session_member(ssid, apply_user_id);
                if(_mysql_chat_session_member->append(mlist) == false){
                    std::string errmsg = "添加会话成员失败";
                    return err_response(rid, errmsg);
                }
            }
            // 6. 组织响应，将新生成的会话 ID 响应给网关
            response->set_request_id(rid);
            response->set_success(true);
            response->set_errmsg("");
            response->set_new_session_id(ssid);
        }

        virtual void FriendSearch(::google::protobuf::RpcController* controller,
                            const ::im::FriendSearchReq* request,
                            ::im::FriendSearchRsp* response,
                            ::google::protobuf::Closure* done){
            LOG_INFO("收到来自 {} 的 用户搜索 请求！", request->request_id());
            brpc::ClosureGuard done_guard(done);
            auto err_response = [response](const std::string &rid, const std::string &msg){
                response->set_request_id(rid);
                response->set_success(false);
                response->set_errmsg(msg);
            };
            // 1. 取出请求中的用户 ID，和搜索关键字
            std::string rid = request->request_id();
            std::string user_id = request->user_id();
            std::string keyword = request->search_key();
            // 2. 从好友关系表中取出该用户所有好友 ID
            std::vector<std::string> friend_ids = _mysql_relation->friends(user_id);
            // 3. 根据关键字从 ES 服务器中进行用户搜索，搜索的时候需要将关键字作为用户ID/手机号/昵称
            // 的搜索关键字进行搜索，且需要根据自己的 ID 和好友 ID 过滤掉自己和自己的好友。
            friend_ids.push_back(user_id);     // 自己和好友为过滤条件
            std::vector<User> users = _es_user->search(keyword, friend_ids);
            // std::remove_if(users.begin(), users.end(), [user_id](const User &u){ return u.user_id() == user_id; }); //前面过滤条件加上了自己，这里就不需要再额外操作了
            
            // 4. 根据搜索到的用户信息中的头像 ID，从用户子服务中批量获取用户头像数据
            std::unordered_set<std::string> user_ids;
            for (auto &u : users) {
                user_ids.insert(u.user_id());
            }
            std::unordered_map<std::string, UserInfo> userinfo_list;
            if(GetUserInfo(rid, user_ids, userinfo_list) == false){
                return err_response(rid, "获取用户信息失败");
            }

            // 5. 组织响应，将搜索到的用户列表响应给网关
            response->set_request_id(rid);
            response->set_success(true);
            response->set_errmsg("");
            for (auto &map : userinfo_list) {
                auto user = map.second;
                response->add_user_info()->CopyFrom(user);
           }
        }

        virtual void GetChatSessionList(::google::protobuf::RpcController* controller,
                            const ::im::GetChatSessionListReq* request,
                            ::im::GetChatSessionListRsp* response,
                            ::google::protobuf::Closure* done){
            LOG_INFO("收到来自 {} 的 获取会话信息 请求！", request->request_id());
            brpc::ClosureGuard done_guard(done);
            auto err_response = [response](const std::string &rid, const std::string &msg){
                response->set_request_id(rid);
                response->set_success(false);
                response->set_errmsg(msg);
            };
            //获取聊天会话的作用：一个用户登录成功后，能够展示自己的历史聊天信息
            // 1. 从请求中取出用户ID 与会话名称，以及会话的成员ID 列表
            std::string rid = request->request_id();
            std::string user_id = request->user_id();
            auto single_chat = _mysql_chat_session->singleChatSession(user_id);
            auto group_chat = _mysql_chat_session->groupChatSession(user_id);
            // 2. 生成会话 ID，并向会话表中新增会话信息数据，会话为群聊会话（单聊会话是同意好友申请的时候创建的）
            std::unordered_set<std::string> user_ids;
            for(auto &s : single_chat){
                user_ids.insert(s.friend_id);
            }
            std::unordered_map<std::string, UserInfo> userinfo_list;
            if(GetUserInfo(rid, user_ids, userinfo_list) == false){
                return err_response(rid, "获取用户信息失败");
            }
            // 3. 组织响应，将组织好的会话信息响应给网关
            response->set_request_id(rid);
            response->set_success(true);
            response->set_errmsg("");
            //    a. 单聊信息
            for(const auto &s : single_chat){
                auto chat_session_info = response->add_chat_session_info_list();
                chat_session_info->set_single_chat_friend_id(s.friend_id);
                chat_session_info->set_chat_session_id(s.chat_session_id);
                chat_session_info->set_chat_session_name(userinfo_list[s.friend_id].nickname());
                chat_session_info->set_avatar(userinfo_list[s.friend_id].avatar());
                MessageInfo msg;
                if(false == GetRecentMsg(rid, s.chat_session_id, msg)){
                    // return err_response(rid, "获取最近消息内容失败");
                    continue;
                }
                chat_session_info->mutable_prev_message()->CopyFrom(msg);
            }
            //    b. 群聊信息
            for(const auto &g : group_chat){
                auto chat_session_info = response->add_chat_session_info_list();
                chat_session_info->set_chat_session_id(g.chat_session_id);
                chat_session_info->set_chat_session_name(g.chat_session_name);
                MessageInfo msg;
                if(false == GetRecentMsg(rid, g.chat_session_id, msg)){
                    // return err_response(rid, "获取最近消息内容失败");
                    continue;
                }
                chat_session_info->mutable_prev_message()->CopyFrom(msg);
            }
        }

        virtual void ChatSessionCreate(::google::protobuf::RpcController* controller,
                            const ::im::ChatSessionCreateReq* request,
                            ::im::ChatSessionCreateRsp* response,
                            ::google::protobuf::Closure* done){
            LOG_INFO("收到来自 {} 的 创建会话 请求！", request->request_id());
            brpc::ClosureGuard done_guard(done);
            auto err_response = [response](const std::string &rid, const std::string &msg){
                response->set_request_id(rid);
                response->set_success(false);
                response->set_errmsg(msg);
            };
            // 1. 从请求中取出用户 ID 与会话名称，以及会话的成员 ID 列表
            std::string rid = request->request_id();
            std::string user_id = request->user_id();
            std::string chat_session_name = request->chat_session_name();
            // 2. 生成会话 ID，并向会话表中新增会话信息数据，会话为群聊会话（单聊会话是同意好友申请的时候创建的）
            std::string csid = uuid();
            ChatSession cs(csid, chat_session_name, ChatSessionType::GROUP);
            if( false == _mysql_chat_session->insert(cs) ){
                LOG_CRITICAL("{} - 向数据库添加会话信息失败: {}", rid, chat_session_name);
                return err_response(rid, "向数据库添加会话信息失败");
            }
            // 3. 向会话成员表中新增所有的成员信息
            std::vector<ChatSessionMember> group_members;
            for(auto &fid : request->member_id_list()){
                group_members.push_back(ChatSessionMember(csid, fid));
            }
            if(false == _mysql_chat_session_member->append(group_members)){
                LOG_CRITICAL("{} - 向数据库添加会话成员信息失败: {}", rid, chat_session_name);
                return err_response(rid, "向数据库添加会话成员信息失败");
            }
            // 4. 组织响应，将组织好的会话信息响应给网关。
            response->set_request_id(rid);
            response->set_success(true);
            response->set_errmsg("");
            response->mutable_chat_session_info()->set_chat_session_id(csid);
            response->mutable_chat_session_info()->set_chat_session_name(chat_session_name);
        }

        virtual void GetChatSessionMember(::google::protobuf::RpcController* controller,
                            const ::im::GetChatSessionMemberReq* request,
                            ::im::GetChatSessionMemberRsp* response,
                            ::google::protobuf::Closure* done){
            LOG_INFO("收到来自 {} 的 获取会话成员 请求！", request->request_id());
            brpc::ClosureGuard done_guard(done);
            auto err_response = [response](const std::string &rid, const std::string &msg){
                response->set_request_id(rid);
                response->set_success(false);
                response->set_errmsg(msg);
            };
            // 1. 取出请求中 用户ID，和 会话ID
            std::string rid = request->request_id();
            std::string user_id = request->user_id();
            std::string csid = request->chat_session_id();
            // 2. 根据会话 ID，从会话成员表&用户表中取出所有的成员用户信息
            auto group_members = _mysql_chat_session_member->members(csid);
            if(group_members.empty()){
                LOG_CRITICAL("{} -获取群聊会话成员信息失败", rid);
                return err_response(rid, "获取群聊会话成员信息失败");
            }
            // 3. 根据成员信息中的头像 ID，从文件存储子服务批量获取头像数据组织用户信息结构
            std::unordered_set<std::string> user_ids;
            for(auto &mid : group_members){
                user_ids.insert(mid);
            }
            std::unordered_map<std::string, UserInfo> userinfo_list;
            if(GetUserInfo(rid, user_ids, userinfo_list) == false){
                return err_response(rid, "获取用户信息失败");
            }
            // 4. 组织响应，将会话的成员用户信息列表响应给网关
            response->set_request_id(rid);
            response->set_success(true);
            for (const auto &uit : userinfo_list) {
                auto user_info = response->add_member_info_list();
                user_info->CopyFrom(uit.second);
            }
        }

        virtual void GetPendingFriendEventList(::google::protobuf::RpcController* controller,
                            const ::im::GetPendingFriendEventListReq* request,
                            ::im::GetPendingFriendEventListRsp* response,
                            ::google::protobuf::Closure* done){
            LOG_INFO("收到来自 {} 的  请求！", request->request_id());
            brpc::ClosureGuard done_guard(done);
            auto err_response = [response](const std::string &rid, const std::string &msg){
                response->set_request_id(rid);
                response->set_success(false);
                response->set_errmsg(msg);
            };
            // 1. 取出请求中的用户 ID
            std::string rid = request->request_id();
            std::string user_id = request->user_id();
            // 2. 根据用户 ID，从申请事件表&用户表中找到该用户所有状态为 PENDING 的待处理事件关联申请人用户简息
            auto applicant_ids = _mysql_apply->applyUsers(user_id);
            // 3. 根据申请人用户头像 ID，从文件存储子服务器获取所有用户头像信息，组织用户信息结构
            std::unordered_set<std::string> user_ids(applicant_ids.begin(), applicant_ids.end());
            std::unordered_map<std::string, UserInfo> userinfo_list;
            if(GetUserInfo(rid, user_ids, userinfo_list) == false){
                return err_response(rid, "获取用户信息失败");
            }
            // 4. 组织响应，将申请事件列表响应给网关
            response->set_request_id(rid);
            response->set_success(true);
            response->set_errmsg("");
            for(auto &map : userinfo_list){
                auto* ev = response->add_event();
                ev->mutable_sender()->CopyFrom(map.second);
            }
        }
    private:
        /// @brief 根据 用户ID 列表，从用户表中获取用户信息
        /// @param rid 请求ID
        /// @param users_id 用户 ID 列表
        /// @param user_list 获取到的用户信息列表
        /// @return bool 调用是否成功
        bool GetUserInfo(const std::string &rid, 
                        const std::unordered_set<std::string> &users_id,
                        std::unordered_map<std::string, UserInfo> &user_list){
            auto channel = _mm_channels->choose(_user_service_name);
            if(channel == nullptr){
                LOG_CRITICAL("{} 没有可供访问的用户子服务节点！",  _user_service_name);
                return false;
            }
            GetMultiUserInfoReq req;
            req.set_request_id(rid);
            for (auto &id : users_id) {
                req.add_users_id(id);
            }
            GetMultiUserInfoRsp rsp;
            brpc::Controller cntl;
            UserService_Stub stub(channel.get());
            stub.GetMultiUserInfo(&cntl, &req, &rsp, nullptr);
            if(cntl.Failed() || rsp.success() == false){
                LOG_CRITICAL("用户子服务节点{}调用失败！-- {}", _user_service_name, cntl.ErrorText());
                return false;
            }
            for(const auto &user : rsp.users_info()){
                user_list.insert(std::make_pair(user.first, user.second));
            }
            return true;
        }

        /// @brief 只获取最近一条消息
        /// @param rid 请求ID
        /// @param cssid 会话ID
        /// @param msg 消息体
        /// @return bool 调用是否成功
        bool GetRecentMsg(const std::string &rid, const std::string &cssid, MessageInfo &msg){
            auto channel = _mm_channels->choose(_message_service_name);
            if(channel == nullptr){
                LOG_CRITICAL("{} 没有可供访问的消息子服务节点！",  _message_service_name);
                return false;
            }
            GetRecentMsgReq req;
            req.set_request_id(rid);
            req.set_chat_session_id(cssid);
            req.set_msg_count(1);
            GetRecentMsgRsp rsp;
            brpc::Controller cntl;
            MsgStorageService_Stub stub(channel.get());
            stub.GetRecentMsg(&cntl, &req, &rsp, nullptr);
            if(cntl.Failed() || rsp.success() == false){
                LOG_CRITICAL("消息子服务节点{}调用失败！-- {}", _message_service_name, cntl.ErrorText());
                return false;
            }
            if(rsp.msg_list_size() == 0){
                return false;
            }
            msg.CopyFrom(rsp.msg_list(0));
            return true;
        }

    private:
        RelationTable::ptr _mysql_relation;
        FriendApplyTable::ptr _mysql_apply;
        ChatSessionTable::ptr _mysql_chat_session;
        ChatSessionMemberTable::ptr _mysql_chat_session_member;

        ESUser::ptr _es_user;

        std::string _user_service_name;
        std::string _message_service_name;
        ServiceManager::ptr _mm_channels;
    };

    class FriendServer{
    public:
        using ptr = std::shared_ptr<FriendServer>;
        FriendServer(const Discover::ptr service_discoverer, 
            const Registry::ptr &reg_client,
            const std::shared_ptr<elasticlient::Client> &es_client,
            const std::shared_ptr<odb::database> &mysql_client,
            const std::shared_ptr<brpc::Server> &server):
            _service_discoverer(service_discoverer),
            _registry_client(reg_client),
            _es_client(es_client),
            _mysql_client(mysql_client),
            _rpc_server(server){}
        void start(){
            _rpc_server->RunUntilAskedToQuit();
        }

    private:
        Discover::ptr _service_discoverer;
        Registry::ptr _registry_client;

        std::shared_ptr<elasticlient::Client> _es_client;
        std::shared_ptr<odb::database> _mysql_client;
        std::shared_ptr<brpc::Server> _rpc_server;
    };

    class FriendServerBuild{
    public:
        FriendServerBuild(){}

        void init_ES_client(const std::vector<std::string> host_list){
            _es_client = ESClientFactory::create(host_list);
        }
        void init_MySql_client(
            const std::string &user, const std::string &pwd,
            const std::string &host, const std::string &db,
            const std::string &cset, int port, int conn_pool_count){
            _mysql_client = ODBFactory::create(user, pwd, host, db, cset, port, conn_pool_count);
        }

        void init_discovery_client(const std::string &reg_host,
            const std::string &base_service_name,
            const std::string &user_service_name,
            const std::string &message_service_name) {
            _user_service_name = user_service_name;
            _message_service_name = message_service_name;
            _mm_channels = std::make_shared<ServiceManager>();
            _mm_channels->declared(user_service_name);
            _mm_channels->declared(message_service_name);
            LOG_DEBUG("设置文件子服务为需添加管理的子服务：{}", user_service_name);
            LOG_DEBUG("设置文件子服务为需添加管理的子服务：{}", message_service_name);
            auto put_cb = std::bind(&ServiceManager::onServiceOnline, _mm_channels.get(), std::placeholders::_1, std::placeholders::_2);
            auto del_cb = std::bind(&ServiceManager::onServiceOffline, _mm_channels.get(), std::placeholders::_1, std::placeholders::_2);
            _service_discoverer = std::make_shared<Discover>(reg_host, base_service_name, put_cb, del_cb);
        }

        void init_register_client(const std::string& reg_host, const std::string& service_name, const std::string& access_host){
            _registry_client = std::make_shared<Registry>(reg_host);        // 登入IP
            _registry_client->register_server(service_name, access_host);   // 注册服务
        }

        void init_rpc_server(uint port, int timeout, int num_threads){
            if (!_es_client) {
                LOG_CRITICAL("还未初始化“ES搜索”模块！");
                abort();
            }
            if (!_mysql_client) {
                LOG_CRITICAL("还未初始化“mysql客户端”模块! ");
                abort();
            }
            if (!_mm_channels) {
                LOG_CRITICAL("还未初始化“信道管理”模块！");
                abort();
            }

            _rpc_server = std::make_shared<brpc::Server>();
            FriendServiceImpl *friend_service = new FriendServiceImpl(_es_client, _mysql_client, _mm_channels, 
                                                                _user_service_name, _message_service_name);
            _rpc_server->AddService(friend_service, brpc::ServiceOwnership::SERVER_OWNS_SERVICE);
            
            brpc::ServerOptions opt;
            opt.idle_timeout_sec = timeout;
            opt.num_threads = num_threads;
            if(_rpc_server->Start(port, &opt) != 0 ){
                LOG_CRITICAL("启动服务器失败！");
                abort();
            }
        }


        FriendServer::ptr Build(){
            if (!_service_discoverer) {
                LOG_CRITICAL("还未初始化“服务发现”模块! ");
                abort();
            }
            if (!_registry_client) {
                LOG_CRITICAL("还未初始化“服务注册”模块！");
                abort();
            }
            if (!_rpc_server) {
                LOG_CRITICAL("还未初始化“RPC服务器”模块! ");
                abort();
            }
            return std::make_shared<FriendServer>(
                    _service_discoverer, _registry_client,
                    _es_client, _mysql_client, _rpc_server
                );
        }

    private:
        std::shared_ptr<elasticlient::Client> _es_client;
        std::shared_ptr<odb::core::database> _mysql_client;

        std::string _user_service_name;
        std::string _message_service_name;
        ServiceManager::ptr _mm_channels;

        Discover::ptr _service_discoverer;
        Registry::ptr _registry_client;
        std::shared_ptr<brpc::Server> _rpc_server;
    };
} // end im